package com.biz.service.HService.schedule.base;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.quartz.CronExpression;
import org.quartz.CronTrigger;
import org.quartz.DateBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.quartz.impl.triggers.SimpleTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.quartz.CronScheduleBuilder;
import org.quartz.Trigger;
import com.alibaba.druid.util.StringUtils;
import com.biz.jobs.base.ScanAllQuartzJob;
import com.biz.model.Pmodel.job.MgroupMesManage;
import com.biz.model.Pmodel.job.MgroupQuartzManage;
import com.biz.model.Pmodel.job.MgroupQuartzManageExample;
import com.biz.model.Pmodel.job.MgroupQuartzManageExample.Criteria;
import com.biz.service.HService.sys.BaseServiceImpl;
import com.framework.dao.hdao.BaseDaoI;
import com.framework.dao.mdao.DaoSupport;

@Service("schedulerService")
public class SchedulerServiceImpl extends BaseServiceImpl<MgroupQuartzManageExample> implements SchedulerServiceI {


	private static final Logger logger =  LoggerFactory.getLogger(SchedulerServiceImpl.class);
	
	@Autowired
	private Scheduler scheduler;

	@Resource(name = "daoSupport")
	private DaoSupport dao;

	public void searchAllJob() throws Exception {
		List<MgroupQuartzManage> jobList = this.getAllNeedDoJob();
		if (!CollectionUtils.isEmpty(jobList)) {
			for (MgroupQuartzManage job : jobList) {
				job = (MgroupQuartzManage) dao.findForObject("MgroupQuartzManageMapper.selectByPrimaryKey",job.getQuartzId());
				if (null != job) {
					logger.info("扫描到新任务，MgroupQuartzManage："+job);
					if (job.getStatus() == MgroupQuartzManage.STATUS_TO_ADD) {
						this.addQuartzManage(job);
					} else if (job.getStatus() == MgroupQuartzManage.STATUS_TO_DELETE) {
						this.deleteQuartzManage(job);
					} else if (job.getStatus() == MgroupQuartzManage.STATUS_TO_UPDATE) {
						this.updateQuartzManage(job);
					} else if (job.getStatus() == MgroupQuartzManage.STATUS_HAS_STOPED) {
						this.deleteQuartzManage(job);
					}else{
						logger.warn("MgroupQuartzManage："+job+",状态值异常");
					}
				}
			}
		}

	}
	
	
	public void init(){
		logger.info("启动quartz扫描任务， 每分钟一次");
	
		this.beginSystemService("scanAllQuartzTask",ScanAllQuartzJob.class, "0 * * * * ? *");
		
		logger.info("结束quartz扫描任务");
	}
	
	public List<MgroupQuartzManage> selectByExample(MgroupQuartzManageExample example) throws Exception{
		return (List<MgroupQuartzManage>) dao.findForList("MgroupQuartzManageMapper.selectByExample",example);
	}
	
	public void beginSystemService(String jobName,Class doJobClass,String cronString){
		try{
			
			String jobroup="systemService";
			
			TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobroup);

			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			if(null!=trigger){
				JobKey jobKey = JobKey.jobKey(jobName, jobroup);
				scheduler.deleteJob(jobKey);
			}
			
			JobDetail jobDetail = JobBuilder.newJob(doJobClass).withIdentity(jobName, jobroup).build();
			
			logger.info("jobDetail:" + jobDetail);
			
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronString);
			
			trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobroup)
					.withSchedule(scheduleBuilder).build();
			logger.info("trigger:" + trigger);
			
			scheduler.scheduleJob(jobDetail, trigger);
			
		}catch(Exception e){
			logger.error("启动quartz扫描任务出错",e);
		}
	}

	/**
	 * 获取所有计划中的任务列表
	 * 
	 * @return
	 * @throws Exception 
	 * @throws SchedulerException
	 */
	public List<MgroupQuartzManage> getAllNeedDoJob() throws Exception {
		MgroupQuartzManageExample mgroupQuartzManageExample = new MgroupQuartzManageExample();
		Criteria criteria = mgroupQuartzManageExample.createCriteria();
		ArrayList<Short> statusList = new ArrayList<Short>();
		statusList.add(MgroupQuartzManage.STATUS_TO_ADD);
		statusList.add(MgroupQuartzManage.STATUS_TO_DELETE);
		statusList.add(MgroupQuartzManage.STATUS_TO_UPDATE);
		criteria.andStatusIn(statusList);
		return (List<MgroupQuartzManage>) dao.findForList("MgroupQuartzManageMapper.selectByExample",mgroupQuartzManageExample);

	}

	/**
	 * 更改任务状态
	 * 
	 * @throws SchedulerException
	 */
	/*
	 * public void changeStatus(ScheduleJob job, String cmd) throws
	 * SchedulerException { if (job == null) { return; } if ("stop".equals(cmd))
	 * { deleteJob(job); job.setJobStatus(ScheduleJob.STATUS_PAUSED); } else if
	 * ("start".equals(cmd)) { job.setJobStatus(ScheduleJob.STATUS_NORMAL);
	 * addJob(job); } baseDao.update(job); }
	 */
	/**
	 * 更改任务 cron表达式
	 * 
	 * @throws SchedulerException
	 */
	/*
	 * public void updateCron(ScheduleJob job, String cron) throws
	 * SchedulerException { if (job == null) { return; }
	 * job.setCronExpression(cron); if
	 * (ScheduleJob.STATUS_NORMAL.equals(job.getJobStatus())) {
	 * updateJobCron(job); } baseDao.update(job);
	 * 
	 * }
	 */

	/**
	 * 添加任务
	 * 
	 * @param job
	 * @throws Exception
	 */
	public boolean addQuartzManage(MgroupQuartzManage job) {

		if (job == null || !isValidExpression(job.getCronExpression())) {
			return false;
		}
		try {
			logger.info(job + "..add");
			TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());

			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			logger.info("trigger:" + trigger);

			// 不存在，创建一个
			if (null == trigger) {

				this.addJob(job);

			} else {

				this.updateJob(job);

			}

			job.setStatus(MgroupQuartzManage.STATUS_HAS_BEGIN);
			dao.update("MgroupQuartzManageMapper.updateByPrimaryKey",job);
			return true;

		} catch (Exception e) {
			logger.error("新增任务出错", e);
			return false;
		}

	}
	
	
	/**
	 * 立即执行该任务
	 * 
	 * @param job
	 * @throws Exception
	 */
	public boolean excuteQuartzManageNow(MgroupQuartzManage job) {

		if (job == null ) {
			return false;
		}
		try {
			logger.info(job + "..add");
			TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());

			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			logger.info("trigger:" + trigger);

			// 已经存在的删除任务 重新建立一个
			if (null != trigger) {

				this.deleteQuartzManage(job);

			} 
			
			Class clazz = Class.forName(job.getBeanClass());
			logger.info("clazz:" + clazz);
			
		    Date startTime = DateBuilder.nextGivenSecondDate(null, 15);

		    // job1 will only fire once at date/time "ts"
		    JobDetail jobDetail  =JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).build();
		    logger.info("jobDetail:" + jobDetail);
			jobDetail.getJobDataMap().put("scheduleJob", job);

		    Trigger tigger =TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup()).startAt(startTime).build();

		    
		    scheduler.scheduleJob(jobDetail, tigger);
		    

			job.setStatus(MgroupQuartzManage.STATUS_HAS_BEGIN);
			dao.update("MgroupQuartzManageMapper.updateByPrimaryKey",job);
			return true;

		} catch (Exception e) {
			logger.error("新增任务出错", e);
			return false;
		}

	}

	/**
	 * 修改任务
	 * 
	 * @param job
	 * @return
	 */
	public boolean updateQuartzManage(MgroupQuartzManage job) {

		if (job == null || !isValidExpression(job.getCronExpression())) {
			return false;
		}
		try {
			logger.info(job + "..update");
			TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());

			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			logger.info("trigger:" + trigger);

			// 修改
			if (null != trigger) {

				this.updateJob(job);

			} else {
				logger.warn("job:" + job + ";任务不存在");
			}

			job.setStatus(MgroupQuartzManage.STATUS_HAS_BEGIN);
			dao.update("MgroupQuartzManageMapper.updateByPrimaryKey",job);
			return true;

		} catch (Exception e) {
			logger.error("新增任务出错", e);
			return false;
		}

	}

	/**
	 * 新增一个quarz任务
	 * 
	 * @param job
	 * @return
	 * @throws Exception
	 */
	public boolean addJob(MgroupQuartzManage job) throws Exception {

		Class clazz = Class.forName(job.getBeanClass());
		logger.info("clazz:" + clazz);
		JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).build();

		logger.info("jobDetail:" + jobDetail);
		jobDetail.getJobDataMap().put("scheduleJob", job);
		Trigger tigger = null;
		if(StringUtils.equals(job.getCronExpression(), MgroupMesManage.CRON_EXPRESSION_NOW)){
			Date startTime = DateBuilder.nextGivenSecondDate(null, 15);
			tigger =TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup()).startAt(startTime).build();
		}else{
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

			tigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup())
					.withSchedule(scheduleBuilder).build();
		}
		
		logger.info("trigger:" + tigger);

		scheduler.scheduleJob(jobDetail, tigger);

		return true;
	}

	/**
	 * 更新一个任务
	 * 
	 * @param job
	 * @return
	 * @throws Exception
	 */
	public boolean updateJob(MgroupQuartzManage job) throws Exception {

		TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
		
		 this.deleteQuartzManage(job);
		  this.addQuartzManage(job);

/*		// Trigger已存在，那么更新相应的定时设置
		CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

		// 按新的cronExpression表达式重新构建trigger
		trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

		// 按新的trigger重新设置job执行
		scheduler.rescheduleJob(triggerKey, trigger);
*/
		return true;
	}
	
	/**
	 * 所有正在运行的job
	 * 
	 * @return
	 * @throws SchedulerException
	 */
	/*
	 * public List<ScheduleJob> getRunningJob() throws SchedulerException { //
	 * Scheduler scheduler = schedulerFactoryBean.getScheduler();
	 * List<JobExecutionContext> executingJobs =
	 * scheduler.getCurrentlyExecutingJobs(); List<ScheduleJob> jobList = new
	 * ArrayList<ScheduleJob>(executingJobs.size()); for (JobExecutionContext
	 * executingJob : executingJobs) { JobDetail jobDetail =
	 * executingJob.getJobDetail(); JobKey jobKey = jobDetail.getKey(); Trigger
	 * trigger = executingJob.getTrigger();
	 * 
	 * ScheduleJob job =
	 * baseDao.getByHql("from ScheduleJob sj where sj.jobName=? and sj.jobGroup=?"
	 * , jobKey.getName(), jobKey.getGroup()); log.info("job:" + job); if (job
	 * == null) { job = new ScheduleJob(); job.setJobName(jobKey.getName());
	 * job.setJobGroup(jobKey.getGroup()); job.setDescription("触发器:" +
	 * trigger.getKey()); }
	 * 
	 * Trigger.TriggerState triggerState =
	 * scheduler.getTriggerState(trigger.getKey());
	 * job.setJobStatus(triggerState.name()); if (trigger instanceof
	 * CronTrigger) { CronTrigger cronTrigger = (CronTrigger) trigger; String
	 * cronExpression = cronTrigger.getCronExpression();
	 * job.setCronExpression(cronExpression); } baseDao.saveOrUpdate(job);
	 * jobList.add(job); } return jobList; }
	 */

	/**
	 * 暂停一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
/*	public void pauseJob(ScheduleJob scheduleJob) throws SchedulerException {

		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		// 暂停任务
		scheduler.pauseJob(jobKey);
	}*/

	/**
	 * 恢复一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
/*	public void resumeJob(ScheduleJob scheduleJob) throws SchedulerException {

		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.resumeJob(jobKey);
	}*/

	/**
	 * 删除一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void deleteQuartzManage(MgroupQuartzManage job) {

		try {
			logger.info(job + "..delete");
			TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
			scheduler.pauseTrigger(triggerKey);// 停止触发器  
			scheduler.unscheduleJob(triggerKey);
			JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
			scheduler.deleteJob(jobKey);

			job.setStatus(MgroupQuartzManage.STATUS_HAS_DELETED);
			dao.update("MgroupQuartzManageMapper.updateByPrimaryKey",job);
		} catch (Exception e) {
			logger.error("删除任务出错", e);
		}

	}


	public void pauseAll() throws SchedulerException {
		scheduler.pauseAll();
	}

	public void resumeAll() throws SchedulerException {
		scheduler.resumeAll();
	}

	/**
	 * 立即执行job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	/*public void runAJobNow(ScheduleJob scheduleJob) throws SchedulerException {
		// Scheduler scheduler = schedulerFactoryBean.getScheduler();
		log.info("scheduler:" + scheduler);
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.triggerJob(jobKey);
	}*/

	/**
	 * 更新job时间表达式
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
/*	public void updateJobCron(ScheduleJob scheduleJob) throws SchedulerException {
		// Scheduler scheduler = schedulerFactoryBean.getScheduler();
		TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
		CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
		if (triggerKey != null) {
			TriggerBuilder<CronTrigger> triggerBuilder = trigger.getTriggerBuilder().withIdentity(triggerKey)
					.withSchedule(scheduleBuilder);
			trigger = triggerBuilder.build();
		}
		scheduler.rescheduleJob(triggerKey, trigger);
	}*/

	private boolean isValidExpression(final String str) {
		CronExpression cronExpression;
		try {
			if(StringUtils.equals(str, MgroupMesManage.CRON_EXPRESSION_NOW)){
				return true;
			}
			cronExpression = new CronExpression(str);
			CronTriggerImpl trigger = new CronTriggerImpl();
			trigger.setCronExpression(cronExpression);
			Date date = trigger.computeFirstFireTime(null);
			boolean isValid = (date != null );
			if (!isValid) {
				logger.info("cron表达式" + str + "出错,date=" + date);
			}
			return isValid;
		} catch (ParseException e) {
			logger.error("解析cron表达式出错", e);
		}
		return false;
	}

	private boolean isValidExpression(final Date startTime) {
		SimpleTriggerImpl trigger = new SimpleTriggerImpl();
		trigger.setStartTime(startTime);
		Date date = trigger.computeFirstFireTime(null);
		return date != null && date.after(new Date());
	}

	
}
